package com.test.lock;

/**
 * @author ：biws
 * @date ：Created in 2020/12/18 22:30
 * @description：
 */
public class Philosopher extends Thread {
    // Shared by all Philosophers
    public final static int N = 5;              // Number of philosophers

    public final static int THINKING = 0;       // Philosopher is thinking
    public final static int HUNGRY = 1;         // Philosopher is hungry
    public final static int EATING = 2;         // Philosopher is eating

    private static int state[] = new int[N];    // Array to keep track of
    // everyones state

    private static Semaphore mutex = new Semaphore(1);  // Mutual exclusion for
    // critical regions
    private static Semaphore s[] = new Semaphore[N];    // One for each
    // Philosopher
    // Instance variable
    public int myNumber;                    // Which philosopher am I
    public int myLeft;                      // Number of my left neighbor
    public int myRight;                     // Number of my right neighbor

    public Philosopher(int i) {             // Make a philosopher
        myNumber = i;
        myLeft = (i + N - 1) % N;               // Compute the left neighbor
        myRight = (i + 1) % N;                // Compute the right neighbor
    }

    public void run() {                     // And away we go
        while (true) {
            think();                        // Philosopher is thinking
            take_forks();                   // Acquire two forks or block
            eat();                          // Yum-yum, spahgetti
            put_forks();                    // Put both forks back on the table
        }
    }

    public void take_forks() {               // Take the forks I need
        mutex.down();                       // Enter critical region
        state[myNumber] = HUNGRY;           // Record the fact that I am hungry
        test(myNumber);                     // Try to acquire two forks
        mutex.up();                         // Leave critical region
        s[myNumber].down();                 // Block if forks were not acquired
    }

    public void put_forks() {
        mutex.down();                       // Enter critical region
        state[myNumber] = THINKING;         // Philosopher has finished eating
        test(myLeft);                       // See if left neighbor can now eat
        test(myRight);                      // See if right neighbor can now
        // eat
        mutex.up();                         // Leave critical region
    }

    public void test(int k) {                // Test philosopher k,
        // from 0 to N-1
        int onLeft = (k + N - 1) % N;           // K's left neighbor
        int onRight = (k + 1) % N;            // K's right neighbor
        if (state[k] == HUNGRY
                && state[onLeft] != EATING
                && state[onRight] != EATING) {

            // Grab those forks
            state[k] = EATING;
            s[k].up();
        }
    }

    public void think() {
        System.out.println("Philosopher " + myNumber + " is thinking");
        try {
            sleep(1000);
        } catch (InterruptedException ex) {
        }
    }

    public void eat() {
        System.out.println("Philosopher " + myNumber + " is eating");
        try {
            sleep(5000);
        } catch (InterruptedException ex) {
        }
    }

    public static void main(String args[]) {

        Philosopher p[] = new Philosopher[N];

        for (int i = 0; i < N; i++) {
            // Create each philosopher and their semaphore
            p[i] = new Philosopher(i);
            s[i] = new Semaphore(0);

            // Start the threads running
            p[i].start();
        }
    }


}


